package me.zhengjie.ppService;

import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.pojo.PPOutBoundParameter;
import me.zhengjie.pojo.sqlServer.*;
import me.zhengjie.repository.*;
import me.zhengjie.service.PPOutboundMissionService;
import me.zhengjie.service.PPOutboundOrderService;
import me.zhengjie.service.PPStorageService;
import me.zhengjie.util.LoginUtil;
import me.zhengjie.util.UniqueCodeUtil;
import me.zhengjie.wcs.PPWmsToWcs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import org.springframework.transaction.annotation.Transactional;

import javax.print.PrintException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: xinglin
 * @CreateTime: 2024-08-14
 * @Description: pp出库
 * @Version: 1.0
 */


@Slf4j
@Component
@RequiredArgsConstructor
public class PPOutBoundService {

    private final PPInventoryRepository ppInventoryRepository;
    private final PPInfoRepository ppInfoRepository;
    private final PPStorageService ppStorageService;
    private final PPOutboundOrderRepository ppOutboundOrderRepository;
    private final PPOutboundOrderDetailRepository ppOutboundOrderDetailRepository;
    private final PPOutboundMissionRepository ppOutboundMissionRepository;
    private final PPWmsTaskRepository ppWmsTaskRepository;
    private final PPWmsToWcs wmsToWcs;
    private final PPOutboundMissionService ppOutboundMissionService;
    private final PPOutboundOrderService ppOutboundOrderService;
    private final PrintConnection printConnection;



    private static final Logger ppLog = LoggerFactory.getLogger("pp");
    private final PpPalletRepository ppPalletRepository;


    /**
     * 根据pp批次，出站口获取需要出库的库存信息
     */
    public List<PPInventory> getInventoryInfo(List<PPOutBoundParameter> ppOutBoundParameterList) {
        List<PPInventory> ppInventoryList = new ArrayList<>();
        for (PPOutBoundParameter ppOutBoundParameter : ppOutBoundParameterList) {
            PPInventory ppInventory = ppInventoryRepository.findByPpBatch(ppOutBoundParameter.getPpBatch());
            if (ppInventory != null && !BeanUtil.isEmpty(ppInventory)&& ppInventory.getStayStatus() == 0) {
                ppInventoryList.add(ppInventory);
            }
        }
        return ppInventoryList;
    }


    /**
     * 保存出库单
     */
    @Transactional
    public PPOutboundOrder saveOutBoundOrder(List<PPOutBoundParameter> ppOutBoundParameterList) {
        List<PPInventory> inventoryList = getInventoryInfo(ppOutBoundParameterList);

        // 锁储位
        List<String> storageCodes = inventoryList.stream().map(PPInventory::getStorageCode).collect(Collectors.toList());
        for (String storageCode : storageCodes) {
            ppStorageService.lockStorage(storageCode);
        }

        // 锁库存
        inventoryList.stream()
                .peek(x -> x.setLockStatus(0))
                .forEach(ppInventoryRepository::save);


        PPOutboundOrder outBoundOrder = new PPOutboundOrder();
        outBoundOrder.setOrderCode(UniqueCodeUtil.createCode());
        outBoundOrder.setOrderType(1);
        outBoundOrder.setOrderStatus(0);
        outBoundOrder.setPriority(0);
        outBoundOrder.setCreateTime(LocalDateTime.now());
        outBoundOrder.setCreateBy(LoginUtil.getLoginUser());
        outBoundOrder.setOutStation(ppOutBoundParameterList.get(0).getOutStation());
        ppOutboundOrderRepository.save(outBoundOrder);

        return outBoundOrder;


    }


    /**
     * 创建出库订单明细
     * @param inventoryList 出库任务参数
     * @return 出库订单明细集合
     */
    @Transactional
    public List<PPOutboundOrderDetail> createOrderDetail(List<PPInventory> inventoryList,String OrderCode) {
        return inventoryList.stream().map(x -> {
            // 保存订单明细
            PPOutboundOrderDetail ppOutboundOrderDetail = new PPOutboundOrderDetail();
            //获取对应的出库单
            PPOutboundOrder ppOutboundOrder = ppOutboundOrderRepository.findPPOutboundOrderByOrderCode(OrderCode);
            ppOutboundOrderDetail.setOutBoundOrderId(ppOutboundOrder.getId());
            PPInfo ppInfo  = ppInfoRepository.getPPInfoByPpBatch(x.getPpBatch());
            ppOutboundOrderDetail.setPpId(ppInfo.getId());
            ppOutboundOrderDetail.setPalletCode(x.getPalletCode());
            ppOutboundOrderDetail.setOutStation(ppOutboundOrder.getOutStation());
            ppOutboundOrderDetailRepository.save(ppOutboundOrderDetail);
            return ppOutboundOrderDetail;
        }).collect(Collectors.toList());

    }

    /**
     * 创建出库订单明细
     * @param inventoryList 出库任务参数
     * @return 出库订单明细集合
     */
    @Transactional
    public List<PPOutboundOrderDetail> createOrderDetailWithoutStation(List<PPInventory> inventoryList,String OrderCode) {
        return inventoryList.stream().map(x -> {
            // 保存订单明细
            PPOutboundOrderDetail ppOutboundOrderDetail = new PPOutboundOrderDetail();
            //获取对应的出库单
            PPOutboundOrder ppOutboundOrder = ppOutboundOrderRepository.findPPOutboundOrderByOrderCode(OrderCode);
            ppOutboundOrderDetail.setOutBoundOrderId(ppOutboundOrder.getId());
            ppOutboundOrderDetail.setPalletCode(x.getPalletCode());
//            ppOutboundOrderDetail.setOutStation(ppOutboundOrder.getOutStation());
            PPInfo ppInfo  = ppInfoRepository.getPPInfoByPpBatch(x.getPpBatch());
            ppOutboundOrderDetail.setPpId(ppInfo.getId());
            ppOutboundOrderDetailRepository.save(ppOutboundOrderDetail);
            return ppOutboundOrderDetail;
        }).collect(Collectors.toList());

    }


    /**
     * 根据订单明细生成出库任务
     * @param ppOutboundOrderDetails 出库请求参数
     */
    @Transactional
    public void createPPOutBoundMission(List<PPOutboundOrderDetail> ppOutboundOrderDetails) {

            List<PPOutboundMission> ppOutBoundMissions = new ArrayList<>();
            for (PPOutboundOrderDetail x : ppOutboundOrderDetails) {
                PPOutboundMission ppOutBoundMission = new PPOutboundMission();
                ppOutBoundMission.setMissionCode(UniqueCodeUtil.createCode());
                ppOutBoundMission.setOutBoundOrderId(x.getOutBoundOrderId());
                ppOutBoundMission.setPriority(ppOutboundOrderRepository.findPriorityById(x.getOutBoundOrderId()));
                //设置状态为已分配任务状态
                ppOutBoundMission.setMissionStatus(0);
                ppOutBoundMission.setPalletCode(x.getPalletCode());

                // 查找储位
                Integer storageId = ppInventoryRepository.findStorageIdByPalletCode(x.getPalletCode());
                String storageCode = ppStorageService.findStorageCodeById(storageId);


                // 设置起点和终点
                ppOutBoundMission.setSource(storageCode);
                ppOutBoundMission.setDestination(x.getOutStation());

                ppOutBoundMission.setCreateTime(LocalDateTime.now());
                PPInfo ppInfo = ppInfoRepository.getById(x.getPpId());
                ppOutBoundMission.setPpId(x.getPpId());
                ppOutBoundMission.setPpQty(ppInfo.getPpQty());

                ppLog.info("出库单id:{}", x.getOutBoundOrderId());
                ppLog.info("创建的出库任务：{}", ppOutBoundMission);

                // 休眠1毫秒
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    ppLog.error("批量生成出库任务时休眠1毫秒出错");
                }
                ppOutBoundMissions.add(ppOutBoundMission);
            }

            ppOutboundMissionRepository.saveAll(ppOutBoundMissions);


    }




    // 将出库任务保存到wms_task
    @Transactional
    public void createOutTask(PPOutboundMission ppOutBoundMission) {
        try {
                // 创建一个新的PPWmsTask对象
                PPWmsTask ppWmsTask = new PPWmsTask();
                ppWmsTask.setLogicalAddressType(1);
                ppWmsTask.setWmsTaskId(ppOutBoundMission.getMissionCode());
                ppWmsTask.setLpnCode(ppOutBoundMission.getPalletCode());
                ppWmsTask.setLpnType(1);
                ppWmsTask.setWcsTaskType(2);
                ppWmsTask.setWarehouseCode("PP");
                ppWmsTask.setAisle(1);
                ppWmsTask.setFromLocation(ppOutBoundMission.getSource());
                ppWmsTask.setToLocation(ppOutBoundMission.getDestination());
                ppWmsTask.setLevel(ppOutBoundMission.getPriority());
                ppWmsTask.setStatus(0);
                ppWmsTask.setCreated(ppOutBoundMission.getCreateTime());
            ppLog.info("生成的wmsTask任务：{}", ppWmsTask);
            // 将出库任务保存到wms_task就是下发任务，定时器从wms_task表中按创建时间取任务发给wcs
            ppWmsTaskRepository.saveAndFlush(ppWmsTask);
        }catch (Exception e){
            ppLog.error("生成wms任务失败：{}",e.getMessage());
        }
    }

    /**
     * 查找所有的出库单
     *
     * @return 出库单列表
     */
    public List<PPOutboundOrder> findAllOrder() {
        return ppOutboundOrderRepository.findAllOrderByCreateTime();
    }




    /**
     * 删除pp出库订单
     *
     * @param orderId 出库单id
     */
    @Transactional
    public void deletePPOutBoundOrder(Integer orderId) {
        List<PPOutboundOrderDetail> details = ppOutboundOrderDetailRepository.findPPOutboundOrderDetailsByOutBoundOrderId(orderId);
        List<String> palletCodes = details.stream().map(PPOutboundOrderDetail::getPalletCode).collect(Collectors.toList());
        List<PPInventory> inventories = ppInventoryRepository.findPPInventoriesInPalletCodes(palletCodes);
        List<String> storageCodes = inventories.stream().map(PPInventory::getStorageCode).collect(Collectors.toList());

        // 释放储位
        storageCodes.forEach(ppStorageService::openStorage);

        // 恢复库存状态
        inventories.stream()
                .peek(x -> x.setLockStatus(1))
                .forEach(ppInventoryRepository::save);

        // 删除出库单对应的出库任务
        ppOutboundMissionRepository.deletePPOutboundMissionByOutBoundOrderId(orderId);

        // 删除出库单对应的出库单明细
        ppOutboundOrderDetailRepository.deletePPOutboundOrderDetailsByOutBoundOrderId(orderId);

        // 最后删除出库单
        ppOutboundOrderRepository.deletePPOutboundOrderById(orderId);
    }


    //找到最早创建的出库任务
    public PPOutboundMission findNewOutBoundMission() {
        if (!ppOutboundMissionRepository.findAllNewPPOutboundMission().isEmpty()) {
            return ppOutboundMissionRepository.findAllNewPPOutboundMission().get(0);
        }else{
            return null;
        }
    }

    /**
     * 发送任务到Pptask中
     */
    // @Transactional(rollbackFor = Exception.class)
    public void sendOutBoundTask(PPOutboundMission ppOutboundMission) {
        PPWmsTask ppWmsTask =  ppWmsTaskRepository.findPPWmsTasksByWmsTaskId(ppOutboundMission.getMissionCode());
//        ppOutboundMissionRepository.updateStatusByMissionCode(String.valueOf(ppWmsTask.getWmsTaskId()),2);
        wmsToWcs.sendTask(ppWmsTask);
    }

    /**
     * 创建出库单要带站点
     * @param parameters 出库单筛选条件
     */
    @Transactional(rollbackFor = Exception.class)
    public PPOutboundOrder createOrder(List<PPOutBoundParameter> parameters) {
        List<PPInventory> inventories = this.getInventoryInfo(parameters);
        PPOutboundOrder ppOutboundOrder=saveOutBoundOrder(parameters);
        List<PPOutboundOrderDetail> ppOutBoundOrderDetails = this.createOrderDetail(inventories,ppOutboundOrder.getOrderCode());
        this.createPPOutBoundMission(ppOutBoundOrderDetails);
        return ppOutboundOrder;
    }

    /**
     * 创建出库单不用带站点
     * @param parameters 出库单筛选条件
     */
    @Transactional(rollbackFor = Exception.class)
    public PPOutboundOrder createOrderWithoutStation(List<PPOutBoundParameter> parameters) {
        List<PPInventory> inventories = this.getInventoryInfo(parameters);
        // 过滤掉过期的库存
        /*inventories = inventories.stream().filter(x -> !x.getDateStatus().equals("exp")).collect(Collectors.toList());*/
        if (!inventories.isEmpty()) {
            PPOutboundOrder ppOutboundOrder = saveOutBoundOrder(parameters);
            //设置为手动出库
            ppOutboundOrder.setOrderType(2);
            ppOutboundOrderRepository.save(ppOutboundOrder);

            List<PPOutboundOrderDetail> ppOutBoundOrderDetails = this.createOrderDetailWithoutStation(inventories, ppOutboundOrder.getOrderCode());
            this.createPPOutBoundMission(ppOutBoundOrderDetails);
            return ppOutboundOrder;

        }else {
            return null;
        }
    }


    public PPInfo getPPInfo(String ppBatch){
        return ppInfoRepository.getPPInfoByPpBatch(ppBatch);
    }


    // 执行出库单
    @Transactional(rollbackFor = Exception.class)
    public void startOutBoundOrder(Integer orderId) {
        List<PPOutboundMission> ppOutBoundMissions = ppOutboundMissionService.findPPOutBoundMissionByOrderId(orderId);

        ppOutboundMissionService.startMission(ppOutBoundMissions);

//        this.createOutTask(ppOutBoundMissions);

        ppOutboundOrderService.startOrder(orderId);

        // 打印pp信息
        this.printPPInfo(orderId);
    }


    //打标机打印PP信息
    public void printPPInfo(Integer orderId) {
        List<PPOutboundOrderDetail> ppOutboundOrderDetails = ppOutboundOrderDetailRepository.findPPOutboundOrderDetailsByOutBoundOrderId(orderId);

        for (PPOutboundOrderDetail ppOutboundOrderDetail : ppOutboundOrderDetails) {
            PpPallet ppPallet =  ppPalletRepository.findByPalletCode(ppOutboundOrderDetail.getPalletCode());
            PPInfo ppInfo = ppInfoRepository.getPPInfoByPpBatch(ppPallet.getPpBatch());
            //打印PP信息
            try {
                printConnection.sendTOPrinter(ppInfo);
            } catch (PrintException e) {
                log.error("打印服务出错，pp信息如下：{}，错误信息:{}",ppInfo,e.toString());
                throw new RuntimeException("打印PP信息失败");
            }
        }

    }




}
